package com.leyou.filters;

import com.leyou.common.auth.dto.Payload;
import com.leyou.common.auth.dto.UserInfo;
import com.leyou.common.auth.utils.JwtUtils;
import com.leyou.common.constants.UserTokenConstants;
import com.leyou.common.utils.CookieUtils;
import com.leyou.config.JwtProperties;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

@Slf4j
@Component
@EnableConfigurationProperties(JwtProperties.class)
public class AuthFilter extends ZuulFilter {
    @Autowired
    private JwtProperties jwtProperties;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private FilterProperties filterProperties;

    /*
    * 过滤器类型,前置
    * */
    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }
    /*
    * 过滤器执行顺序，数字越小，优先级越高
    * */
    @Override
    public int filterOrder() {
        return FilterConstants.FORM_BODY_WRAPPER_FILTER_ORDER+1;
    }
    /*
    * 返回true:run方法会被执行，返回false：run方法不会执行
    * */
    @Override
    public boolean shouldFilter() {
        //获取上下文
        RequestContext ctx = RequestContext.getCurrentContext();
        //获取request
        HttpServletRequest request = ctx.getRequest();
        //判断是否放行
        boolean isAllow = isAllowRequest(request);
        //如果是需要放行的，这里要返回false,否则返回true
        return !isAllow;
    }
    /*
    * 判断是否放行逻辑
    * */
    private boolean isAllowRequest(HttpServletRequest request){
        //1.获取请求路径
        String path = request.getRequestURI();
        //2.获取请求方法
        String method = request.getMethod();
        //3.判断
        for (Map.Entry<String, String> entry : filterProperties.getAllowPathMap().entrySet()) {
            //取出path
            String allowPath = entry.getKey();
            //取出method
            String allowMethod = entry.getValue();
            if(path.startsWith(allowPath)&&("*".equals(allowMethod)|| allowMethod.equals(method))){
                return true;
            }
        }
        return false;
    }

    /*
    * 过滤器具体逻辑
    * */
    @Override
    public Object run() throws ZuulException {
        //1.获取上下文
        RequestContext ctx = RequestContext.getCurrentContext();
        //2.获取request
        HttpServletRequest request = ctx.getRequest();
        try {
        //3.获取cookie中的token
        String token = CookieUtils.getCookieValue(request, UserTokenConstants.COOKIE_NAME);
            //4.解析token
            Payload<UserInfo> payload = JwtUtils.getInfoFromToken(token, jwtProperties.getPublicKey(), UserInfo.class);
            //5.校验黑名单
            Boolean boo = redisTemplate.hasKey(payload.getId());
            if(BooleanUtils.isTrue(boo)){
                //证明存在于黑名单,说明token已经登出过，无效
                throw  new RuntimeException("token无效");
            }
            //6.权限控制
            UserInfo user = payload.getUserInfo();
            //获取用户角色,查询权限
            String role = user.getRole();
            //获取当前资源路径
            String path = request.getRequestURI();
            String method = request.getMethod();
            //TODO 判断权限，此处暂时空置，等待权限服务完成后补充
            log.info("[网关]用户{},角色{}。访问服务{}:{},",user.getUsername(),role,method,path);
        } catch (RuntimeException e) {
            //拦截请求
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(403);
            log.error("非法访问,未登录，地址:{}",request.getRemoteHost(),e);
        }
        return null;

    }
}
